﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HP.UtilsLib
{
    public interface ITaskAwaiter<TResult>: IDisposable
    {
        TResult GetResult();
        void Await();
    }
    public interface ITaskAwaiter: IDisposable
    {
        void Await();
    }
    public static class TaskAwaiterHelper
    {
        private class TaskAwaiter<TResult> : ITaskAwaiter<TResult>
        {
            private ManualResetEvent waiter = new ManualResetEvent(false);
            public TaskAwaiter(Func<TResult> function)
            {
                Task.Run(
                     () => {
                        result=function();
                        waiter.Set();
                    }
                );
            }
            public TaskAwaiter(Func<Task<TResult>> function)
            {
                Task.Run(
                    async () =>
                    {
                        result = await function().ConfigureAwait(false);
                        waiter.Set();
                    }
                );
            }
            private TResult result;
            public void Await()
            {
                waiter.WaitOne();
            }

            public TResult GetResult()
            {
                Await();
                return result;
            }

            public void Dispose()
            {
                waiter.Dispose();
            }
        }

        private class TaskAwaiter : ITaskAwaiter
        {
            private ManualResetEvent waiter = new ManualResetEvent(false);
            public TaskAwaiter(Action action)
            {
                Task.Run(
                    () => {
                        action();
                        waiter.Set();
                    }
                );
            }
            public TaskAwaiter(Func<Task> function)
            {
                Task.Run(
                    async () => {
                        await function().ConfigureAwait(false);
                        waiter.Set();
                    }
                );
            }
            public void Await()
            {
                waiter.WaitOne();
            }

            public void Dispose()
            {
                waiter.Dispose();
            }
        }

        public static ITaskAwaiter<TResult> GetTaskAwaiter<TResult>(Func<TResult> function)
        {
            TaskAwaiter<TResult> taskAwaiter = new TaskAwaiter<TResult>(function);
            return taskAwaiter;
        }
        public static ITaskAwaiter GetTaskAwaiter(Func<Task> function)
        {
            TaskAwaiter taskAwaiter = new TaskAwaiter(function);
            return taskAwaiter;
        }
        public static ITaskAwaiter<TResult> GetTaskAwaiter<TResult>(Func<Task<TResult>> function)
        {
            TaskAwaiter<TResult> taskAwaiter = new TaskAwaiter<TResult>(function);
            return taskAwaiter;
        }
        public static ITaskAwaiter GetTaskAwaiter(Action function)
        {
            TaskAwaiter taskAwaiter = new TaskAwaiter(function);
            return taskAwaiter;
        }
    }
}
